﻿//l_request.cpp
/*
  (C)
  */

#include "request.hpp"
#include "l_request.hpp"
#include <iostream>


namespace http {
	namespace server3 {

		const char* l_request_metatable = "l_request_metatable";
        int l_request_get_Slave_ID(lua_State *L){
            request * req = l_get_request(L);
            if(req != NULL){
                const char *uri = req->uri.c_str();
                uri++; // ignore uri[0]='/'
                const char *ptr = uri;
                while(*ptr!='?'&&*ptr) ptr++;
                if(!*ptr) return 0; // biz not found
                lua_pushlstring(L,uri,ptr-uri);
                return 1;
            }
            return 0;
        }

        static int l_request_getMethod(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){
                std::string &method = req->method;
                lua_pushlstring(L, method.c_str(),method.length());
                return 1;
            }
            return 0;
        }
        static int l_request_getUri(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){
                std::string &uri = req->uri;
                lua_pushlstring(L, uri.c_str(),uri.length());
				return 1;
            };
			return 0;
		}

        /************************************************************************/
        /* table request::getParameters_key_value()
            return table of header in key-value form: (key [header name], value [header value])
        */
        /************************************************************************/
        static int l_request_getParamsKV(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){
                // param_seperator
                const char *seperators;                
                seperators = luaL_optstring(L,1,"&=");
                const char *uri = req->uri.c_str();
                while(*uri!='?'&&*uri) uri++;
                if(!*uri) return 0; // biz not found
                uri++; // ignore '?'
                const char *ptr = uri;
                int pushed=0;
                const char* ptrsep;
                lua_createtable(L,0,8); // preallocate 8 table entries
                while (*ptr) {
                    ptrsep = seperators; // reset ptrsep
                    while(*ptr!=*ptrsep&&*ptrsep) ptrsep++; // compare every char
                    ptr++;
                    if(!*ptrsep) continue; // not found
                    lua_pushlstring(L,uri,ptr-uri-1);
                    uri = ptr;
                    pushed++;
                    if(pushed==2) { // have key and value
                        lua_rawset(L,-3);
                        pushed=0;
                    }
                }
                if(pushed == 1) { // last value
                    lua_pushlstring(L,uri,ptr-uri-1);
                    lua_rawset(L,-3);
                }
            }
            else lua_newtable(L);
            return 1;
        }
        static int l_request_getParams(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){
                // param_seperator
                const char *seperators;
                seperators = luaL_optstring(L,1,";");
                const char *uri = req->uri.c_str();
                while(*uri!='?'&&*uri) uri++;
                if(!*uri) return 0; // biz not found
                uri++; // ignore '?'
                const char *ptr = uri;
                const char* ptrsep;
                int paramID = 1;
                lua_createtable(L,8,0); // preallocate 8 array entries
                while (*ptr) {
                    ptrsep = seperators; // reset ptrsep
                    while(*ptr!=*ptrsep&&*ptrsep) ptrsep++; // compare every char
                    ptr++;
                    if(!*ptrsep) continue; // not found
                    lua_pushnumber(L,paramID++);
                    lua_pushlstring(L,uri,ptr-uri-1);
                    lua_rawset(L,-3);
                    uri = ptr;
                }
                if(ptr!=uri) { // last value
                    lua_pushnumber(L,paramID);
                    lua_pushlstring(L,uri,ptr-uri-1);
                    lua_rawset(L,-3);
                }
            }
            else lua_newtable(L);
            return 1;
        }      

        static int l_request_getHeaders_key_value(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){                
                int size = req->headers.size();
                lua_createtable(L,0,size);
                for(int i = 0; i < size; i++){
                    header &h = req->headers[i];
                    std::string &n = h.name;
                    std::string &v = h.value;
                    lua_pushlstring(L, n.c_str(),n.length());
                    lua_pushlstring(L, v.c_str(),v.length());
                    lua_rawset(L, -3);
                }
                return 1;
            }
            else lua_newtable(L);
            return 1;
        }

        static int l_request_getPort(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){                
                lua_pushnumber(L, req->port);
                return 1;
            }
            return 0;
        }
        static int l_request_getIP(lua_State* L){
            request * req = l_get_request(L);
            if(req != NULL){
                std::string &ip = req->ip;
                lua_pushlstring(L, ip.c_str(),ip.length());
                return 1;
            }
            return 0;
        }

        static luaL_reg regArr[] = {
                {"getMethod", l_request_getMethod},
                {"getUri", l_request_getUri},
                {"getPort", l_request_getPort},
                {"getIP", l_request_getIP},
                {"getSlaveID", l_request_get_Slave_ID},
                {"getHeadersKV", l_request_getHeaders_key_value},
                {"getParamsKV", l_request_getParamsKV},
                {"getParams", l_request_getParams},
                {NULL, NULL}
            };

        int l_register_request(lua_State* L){            
            luaL_register(L, "request", regArr);
            return 1;
		}

	}
}

/*
The thread environment (where global variables live) is always at pseudo-index LUA_GLOBALSINDEX.
The environment of the running C function is always at pseudo-index LUA_ENVIRONINDEX.

#define LUA_REGISTRYINDEX	(-10000)
#define LUA_ENVIRONINDEX	(-10001)
#define LUA_GLOBALSINDEX	(-10002)

index # 0
index > 0 : value at L->base + index-1
index < 0 : value at L->top + index
1 <= abs(index) <= top


The following example shows how the host program can do the equivalent to this Lua code:

     a = f("how", t.x, 14)

Here it is in C:

     lua_getfield(L, LUA_GLOBALSINDEX, "f"); // function to be called
     -- at global index is the thread object
            -- L[base] = thread["f"]
     lua_pushstring(L, "how");                        // 1st argument
            -- L[base+1] = "how"
     lua_getfield(L, LUA_GLOBALSINDEX, "t");   // table to be indexed
            -- L[base+2] = thread["t"] = L[top]
     lua_getfield(L, -1, "x");        // push result of t.x (2nd arg)
      = lua_getfield(L,2,"x")
            -- L[base+3] = L[base+2]["x"]
     lua_remove(L, -2);                  // remove 't' from the stack
            -- L[base+2] = L[base+3]
     lua_pushinteger(L, 14);                          // 3rd argument
            -- L[base+3] = 14
     lua_call(L, 3, 1);     // call 'f' with 3 arguments and 1 result
            -- call L[base] with 3 arguments;
            -- return value at L[top]; for 1 return value top = base
     lua_setfield(L, LUA_GLOBALSINDEX, "a");        // set global 'a'
            --thread["a"] = L[top]; top--;
Note that the code above is "balanced": at its end, the stack is back to its original configuration.
This is considered good programming practice.
*/
